package reflectTool

import (
	"encoding/json"
	"fmt"
	"reflect"
)

// JSONToStruct
//
//	@Description:  使用反射将 JSON 字符串填充到结构体字段中
//	@Param: jsonStr json字符串
//	@Param: dest 传入的结构体
//	@Return: error
func JSONToStruct_Testing(jsonStr string, dest interface{}) error {
	// 创建一个 map，用于存储 JSON 数据
	var data map[string]interface{}

	// 解析 JSON 字符串到 map 中
	err := json.Unmarshal([]byte(jsonStr), &data)
	if err != nil {
		return fmt.Errorf("failed to unmarshal JSON: %v", err)
	}

	// 获取目标结构体的类型和值
	reflect.TypeOf(dest).Elem()
	destValue := reflect.ValueOf(dest).Elem()

	// 遍历 map 中的键值对
	for key, value := range data {
		// 在结构体中查找字段名与键名相同的字段
		field := destValue.FieldByName(key)
		if !field.IsValid() {
			return fmt.Errorf("field '%s' not found in struct", key)
		}

		// 将值转换为结构体字段的类型，并设置字段值
		fieldType := field.Type()
		if fieldType.Kind() == reflect.Ptr && value != nil {
			// 如果字段是指针类型且值不为nil，则创建一个新的字段值并设置
			newFieldValue := reflect.New(fieldType.Elem())
			if err := setValue(newFieldValue.Interface(), value); err != nil {
				return fmt.Errorf("failed to set field '%s': %v", key, err)
			}
			field.Set(newFieldValue)
		} else if fieldType.Kind() != reflect.Ptr {
			// 如果字段不是指针类型，则直接设置字段值
			if err := setValue(field.Addr().Interface(), value); err != nil {
				return fmt.Errorf("failed to set field '%s': %v", key, err)
			}
		} else {
			return fmt.Errorf("unsupported field type for field '%s'", key)
		}
	}

	return nil
}

// setValue 设置目标值的函数
func setValue(target interface{}, value interface{}) error {
	targetValue := reflect.ValueOf(target)
	if !targetValue.IsValid() || targetValue.Kind() != reflect.Ptr {
		return fmt.Errorf("target must be a pointer")
	}
	targetValue = targetValue.Elem()

	// 如果目标值是零值，则创建一个新的目标值并设置
	if !targetValue.IsValid() || targetValue.IsZero() {
		targetValue.Set(reflect.New(targetValue.Type()).Elem())
	}

	// 设置目标值的值
	switch targetValue.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		v, ok := value.(float64)
		if !ok {
			return fmt.Errorf("value must be a number for target type %s", targetValue.Kind())
		}
		targetValue.SetInt(int64(v))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		v, ok := value.(float64)
		if !ok {
			return fmt.Errorf("value must be a number for target type %s", targetValue.Kind())
		}
		targetValue.SetUint(uint64(v))
	case reflect.Float32, reflect.Float64:
		v, ok := value.(float64)
		if !ok {
			return fmt.Errorf("value must be a number for target type %s", targetValue.Kind())
		}
		targetValue.SetFloat(v)
	case reflect.String:
		v, ok := value.(string)
		if !ok {
			return fmt.Errorf("value must be a string for target type %s", targetValue.Kind())
		}
		targetValue.SetString(v)
	case reflect.Bool:
		v, ok := value.(bool)
		if !ok {
			return fmt.Errorf("value must be a boolean for target type %s", targetValue.Kind())
		}
		targetValue.SetBool(v)
	default:
		return fmt.Errorf("unsupported target type: %s", targetValue.Kind())
	}

	return nil
}
